using System;
using System.Collections.Generic;
using System.Linq;

namespace MT5Trade.Models
{
    /// <summary>
    /// 价格缺口类型枚举
    /// </summary>
    public enum GapType
    {
        /// <summary>
        /// 无缺口
        /// </summary>
        None,
        /// <summary>
        /// 普通缺口：横盘整理中出现的小缺口
        /// </summary>
        Common,
        /// <summary>
        /// 突破缺口：突破重要阻力/支撑位时形成的缺口
        /// </summary>
        Breakaway,
        /// <summary>
        /// 持续缺口：趋势中途出现的缺口，又称逃逸缺口
        /// </summary>
        Runaway,
        /// <summary>
        /// 持续缺口（别名，为了兼容性）
        /// </summary>
        Continuation = Runaway,
        /// <summary>
        /// 衰竭缺口：趋势末期出现的缺口
        /// </summary>
        Exhaustion
    }

    /// <summary>
    /// 缺口方向枚举
    /// </summary>
    public enum GapDirection
    {
        /// <summary>
        /// 向上缺口
        /// </summary>
        Up,
        /// <summary>
        /// 向下缺口
        /// </summary>
        Down
    }

    /// <summary>
    /// 缺口数据结构
    /// </summary>
    public class GapData
    {
        /// <summary>
        /// 缺口发生时间
        /// </summary>
        public DateTime Time { get; set; }

        /// <summary>
        /// 缺口类型
        /// </summary>
        public GapType Type { get; set; }

        /// <summary>
        /// 缺口方向
        /// </summary>
        public GapDirection Direction { get; set; }

        /// <summary>
        /// 缺口大小（点数）
        /// </summary>
        public double GapSize { get; set; }

        /// <summary>
        /// 缺口大小（百分比）
        /// </summary>
        public double GapPercentage { get; set; }

        /// <summary>
        /// 前一日收盘价
        /// </summary>
        public double PreviousClose { get; set; }

        /// <summary>
        /// 开盘价
        /// </summary>
        public double OpenPrice { get; set; }

        /// <summary>
        /// 是否已填补
        /// </summary>
        public bool IsFilled { get; set; }

        /// <summary>
        /// 填补时间
        /// </summary>
        public DateTime? FillTime { get; set; }

        /// <summary>
        /// 持续时间（分钟）
        /// </summary>
        public int DurationMinutes { get; set; }

        /// <summary>
        /// 成交量
        /// </summary>
        public double Volume { get; set; }

        /// <summary>
        /// 缺口填补概率预测
        /// </summary>
        public double FillProbability { get; set; }

        /// <summary>
        /// 置信度
        /// </summary>
        public double Confidence { get; set; }
    }

    /// <summary>
    /// 市场数据点
    /// </summary>
    public class MarketDataPoint
    {
        public DateTime Time { get; set; }
        public double Open { get; set; }
        public double High { get; set; }
        public double Low { get; set; }
        public double Close { get; set; }
        public double Volume { get; set; }
    }

    /// <summary>
    /// 缺口统计信息
    /// </summary>
    public class GapStatistics
    {
        /// <summary>
        /// 总缺口数量
        /// </summary>
        public int TotalGaps { get; set; }

        /// <summary>
        /// 各类型缺口数量
        /// </summary>
        public Dictionary<GapType, int> GapTypeCount { get; set; } = new Dictionary<GapType, int>();

        /// <summary>
        /// 各类型填补率
        /// </summary>
        public Dictionary<GapType, double> FillRateByType { get; set; } = new Dictionary<GapType, double>();

        /// <summary>
        /// 平均缺口大小
        /// </summary>
        public double AverageGapSize { get; set; }

        /// <summary>
        /// 平均填补时间
        /// </summary>
        public double AverageFillTimeMinutes { get; set; }

        /// <summary>
        /// 整体填补率
        /// </summary>
        public double OverallFillRate { get; set; }

        /// <summary>
        /// 向上缺口比例
        /// </summary>
        public double UpGapPercentage { get; set; }
    }

    /// <summary>
    /// 价格缺口分析器
    /// 实现缺口识别、分类、统计和预测功能
    /// </summary>
    public class GapAnalyzer
    {
        #region 私有字段

        /// <summary>
        /// 历史市场数据
        /// </summary>
        private readonly List<MarketDataPoint> _historicalData;

        /// <summary>
        /// 检测到的缺口列表
        /// </summary>
        private readonly List<GapData> _detectedGaps;

        /// <summary>
        /// 缺口检测阈值（最小缺口大小，点数）
        /// </summary>
        private const double MIN_GAP_SIZE = 5.0;

        /// <summary>
        /// 缺口检测阈值（最小缺口百分比）
        /// </summary>
        private const double MIN_GAP_PERCENTAGE = 0.1; // 0.1%

        /// <summary>
        /// 突破缺口判定阈值（波动率倍数）
        /// </summary>
        private const double BREAKAWAY_MULTIPLIER = 2.0;

        /// <summary>
        /// 衰竭缺口判定的成交量阈值倍数
        /// </summary>
        private const double EXHAUSTION_VOLUME_MULTIPLIER = 1.5;

        #endregion

        #region 构造函数

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="historicalData">历史市场数据</param>
        public GapAnalyzer(List<MarketDataPoint> historicalData = null)
        {
            _historicalData = historicalData ?? new List<MarketDataPoint>();
            _detectedGaps = new List<GapData>();
        }

        #endregion

        #region 公共方法

        /// <summary>
        /// 检测价格缺口
        /// </summary>
        /// <param name="data">市场数据，如果为null则使用历史数据</param>
        /// <returns>检测到的缺口列表</returns>
        public List<GapData> DetectGaps(List<MarketDataPoint> data = null)
        {
            var marketData = data ?? _historicalData;
            if (marketData == null || marketData.Count < 2)
                return new List<GapData>();

            _detectedGaps.Clear();

            // 按时间排序
            var sortedData = marketData.OrderBy(x => x.Time).ToList();

            for (int i = 1; i < sortedData.Count; i++)
            {
                var current = sortedData[i];
                var previous = sortedData[i - 1];

                // 计算缺口
                var gap = AnalyzeGap(previous, current, sortedData, i);
                if (gap != null)
                {
                    _detectedGaps.Add(gap);
                }
            }

            // 检查缺口填补状况
            UpdateGapFillStatus(sortedData);

            return _detectedGaps.ToList();
        }

        /// <summary>
        /// 分析单个缺口
        /// </summary>
        /// <param name="previous">前一个数据点</param>
        /// <param name="current">当前数据点</param>
        /// <param name="allData">所有数据</param>
        /// <param name="currentIndex">当前索引</param>
        /// <returns>缺口数据，如果无缺口则返回null</returns>
        private GapData AnalyzeGap(MarketDataPoint previous, MarketDataPoint current, List<MarketDataPoint> allData, int currentIndex)
        {
            // 检查是否存在缺口
            bool hasUpGap = current.Low > previous.High;
            bool hasDownGap = current.High < previous.Low;

            if (!hasUpGap && !hasDownGap)
                return null;

            // 计算缺口大小
            double gapSize;
            GapDirection direction;

            if (hasUpGap)
            {
                gapSize = current.Low - previous.High;
                direction = GapDirection.Up;
            }
            else
            {
                gapSize = previous.Low - current.High;
                direction = GapDirection.Down;
            }

            // 计算缺口百分比
            double gapPercentage = (gapSize / previous.Close) * 100;

            // 检查缺口是否达到最小阈值
            if (gapSize < MIN_GAP_SIZE && Math.Abs(gapPercentage) < MIN_GAP_PERCENTAGE)
                return null;

            // 创建缺口数据
            var gap = new GapData
            {
                Time = current.Time,
                Direction = direction,
                GapSize = gapSize,
                GapPercentage = gapPercentage,
                PreviousClose = previous.Close,
                OpenPrice = current.Open,
                Volume = current.Volume,
                IsFilled = false
            };

            // 分类缺口类型
            gap.Type = ClassifyGapType(gap, allData, currentIndex);

            // 预测填补概率
            gap.FillProbability = PredictFillProbability(gap, allData, currentIndex);
            gap.Confidence = CalculateConfidence(gap, allData, currentIndex);

            return gap;
        }

        /// <summary>
        /// 分类缺口类型
        /// </summary>
        /// <param name="gap">缺口数据</param>
        /// <param name="allData">所有市场数据</param>
        /// <param name="currentIndex">当前索引</param>
        /// <returns>缺口类型</returns>
        private GapType ClassifyGapType(GapData gap, List<MarketDataPoint> allData, int currentIndex)
        {
            // 计算前期波动率
            var volatility = CalculateVolatility(allData, currentIndex, 20);
            
            // 计算趋势强度
            var trendStrength = CalculateTrendStrength(allData, currentIndex, 10);
            
            // 计算成交量相对强度
            var volumeRatio = CalculateVolumeRatio(allData, currentIndex, 10);

            // 分类逻辑
            
            // 1. 突破缺口：缺口较大，成交量高，突破重要价位
            if (Math.Abs(gap.GapPercentage) > volatility * BREAKAWAY_MULTIPLIER && 
                volumeRatio > 1.2 && 
                IsBreakingImportantLevel(gap, allData, currentIndex))
            {
                return GapType.Breakaway;
            }

            // 2. 衰竭缺口：趋势末期，成交量异常高，缺口较大但后续无力
            if (Math.Abs(trendStrength) > 0.7 && 
                volumeRatio > EXHAUSTION_VOLUME_MULTIPLIER && 
                Math.Abs(gap.GapPercentage) > volatility * 1.5 &&
                IsLikelyTrendExhaustion(allData, currentIndex))
            {
                return GapType.Exhaustion;
            }

            // 3. 持续缺口：趋势中期，适中的缺口和成交量
            if (Math.Abs(trendStrength) > 0.4 && 
                Math.Abs(gap.GapPercentage) > volatility * 1.0 &&
                volumeRatio > 0.8 && volumeRatio < 1.5)
            {
                return GapType.Runaway;
            }

            // 4. 普通缺口：其他情况
            return GapType.Common;
        }

        /// <summary>
        /// 预测缺口填补概率
        /// </summary>
        /// <param name="gap">缺口数据</param>
        /// <param name="allData">所有数据</param>
        /// <param name="currentIndex">当前索引</param>
        /// <returns>填补概率（0-1）</returns>
        private double PredictFillProbability(GapData gap, List<MarketDataPoint> allData, int currentIndex)
        {
            // 基础填补概率（根据历史统计）
            var baseProbability = GetHistoricalFillRate(gap.Type);

            // 根据缺口大小调整
            var sizeAdjustment = CalculateSizeAdjustment(gap.GapPercentage);

            // 根据成交量调整
            var volumeAdjustment = CalculateVolumeAdjustment(allData, currentIndex);

            // 根据市场趋势调整
            var trendAdjustment = CalculateTrendAdjustment(allData, currentIndex);

            // 综合计算
            var probability = baseProbability * sizeAdjustment * volumeAdjustment * trendAdjustment;

            return Math.Max(0.0, Math.Min(1.0, probability));
        }

        /// <summary>
        /// 更新缺口填补状态
        /// </summary>
        /// <param name="allData">所有市场数据</param>
        private void UpdateGapFillStatus(List<MarketDataPoint> allData)
        {
            foreach (var gap in _detectedGaps)
            {
                if (gap.IsFilled) continue;

                var gapData = allData.FirstOrDefault(x => x.Time == gap.Time);
                if (gapData == null) continue;

                var gapIndex = allData.IndexOf(gapData);
                
                // 检查后续数据中是否填补了缺口
                for (int i = gapIndex + 1; i < allData.Count; i++)
                {
                    var current = allData[i];
                    bool filled = false;

                    if (gap.Direction == GapDirection.Up)
                    {
                        // 向上缺口：价格回落到前一日最高价以下
                        filled = current.Low <= gap.PreviousClose;
                    }
                    else
                    {
                        // 向下缺口：价格回升到前一日最低价以上
                        filled = current.High >= gap.PreviousClose;
                    }

                    if (filled)
                    {
                        gap.IsFilled = true;
                        gap.FillTime = current.Time;
                        gap.DurationMinutes = (int)(current.Time - gap.Time).TotalMinutes;
                        break;
                    }
                }
            }
        }

        /// <summary>
        /// 获取缺口统计信息
        /// </summary>
        /// <returns>统计信息</returns>
        public GapStatistics GetStatistics()
        {
            if (!_detectedGaps.Any())
                return new GapStatistics();

            var stats = new GapStatistics
            {
                TotalGaps = _detectedGaps.Count,
                AverageGapSize = _detectedGaps.Average(x => Math.Abs(x.GapSize)),
                OverallFillRate = (double)_detectedGaps.Count(x => x.IsFilled) / _detectedGaps.Count,
                UpGapPercentage = (double)_detectedGaps.Count(x => x.Direction == GapDirection.Up) / _detectedGaps.Count
            };

            // 统计各类型缺口数量
            foreach (GapType type in Enum.GetValues(typeof(GapType)))
            {
                var typeGaps = _detectedGaps.Where(x => x.Type == type).ToList();
                stats.GapTypeCount[type] = typeGaps.Count;
                
                if (typeGaps.Any())
                {
                    stats.FillRateByType[type] = (double)typeGaps.Count(x => x.IsFilled) / typeGaps.Count;
                }
                else
                {
                    stats.FillRateByType[type] = 0.0;
                }
            }

            // 计算平均填补时间
            var filledGaps = _detectedGaps.Where(x => x.IsFilled && x.DurationMinutes > 0).ToList();
            if (filledGaps.Any())
            {
                stats.AverageFillTimeMinutes = filledGaps.Average(x => x.DurationMinutes);
            }

            return stats;
        }

        /// <summary>
        /// 获取指定类型的缺口列表
        /// </summary>
        /// <param name="gapType">缺口类型</param>
        /// <returns>缺口列表</returns>
        public List<GapData> GetGapsByType(GapType gapType)
        {
            return _detectedGaps.Where(x => x.Type == gapType).ToList();
        }

        /// <summary>
        /// 获取最近的缺口
        /// </summary>
        /// <param name="count">数量</param>
        /// <returns>最近的缺口列表</returns>
        public List<GapData> GetRecentGaps(int count = 10)
        {
            return _detectedGaps.OrderByDescending(x => x.Time).Take(count).ToList();
        }

        #endregion

        #region 辅助方法

        /// <summary>
        /// 计算历史波动率
        /// </summary>
        private double CalculateVolatility(List<MarketDataPoint> data, int currentIndex, int period)
        {
            var startIndex = Math.Max(0, currentIndex - period);
            var periodData = data.Skip(startIndex).Take(currentIndex - startIndex).ToList();

            if (periodData.Count < 2) return 0.01; // 默认1%波动率

            var returns = new List<double>();
            for (int i = 1; i < periodData.Count; i++)
            {
                var ret = Math.Log(periodData[i].Close / periodData[i - 1].Close);
                returns.Add(ret);
            }

            var avgReturn = returns.Average();
            var variance = returns.Select(x => Math.Pow(x - avgReturn, 2)).Average();
            
            return Math.Sqrt(variance) * 100; // 转换为百分比
        }

        /// <summary>
        /// 计算趋势强度
        /// </summary>
        private double CalculateTrendStrength(List<MarketDataPoint> data, int currentIndex, int period)
        {
            var startIndex = Math.Max(0, currentIndex - period);
            var periodData = data.Skip(startIndex).Take(currentIndex - startIndex + 1).ToList();

            if (periodData.Count < 2) return 0.0;

            // 简单线性回归计算趋势强度
            var n = periodData.Count;
            var sumX = 0.0;
            var sumY = 0.0;
            var sumXY = 0.0;
            var sumX2 = 0.0;

            for (int i = 0; i < n; i++)
            {
                sumX += i;
                sumY += periodData[i].Close;
                sumXY += i * periodData[i].Close;
                sumX2 += i * i;
            }

            var slope = (n * sumXY - sumX * sumY) / (n * sumX2 - sumX * sumX);
            var avgPrice = sumY / n;
            
            // 标准化趋势强度
            return slope / avgPrice;
        }

        /// <summary>
        /// 计算成交量比率
        /// </summary>
        private double CalculateVolumeRatio(List<MarketDataPoint> data, int currentIndex, int period)
        {
            var startIndex = Math.Max(0, currentIndex - period);
            var periodData = data.Skip(startIndex).Take(currentIndex - startIndex).ToList();

            if (periodData.Count == 0) return 1.0;

            var avgVolume = periodData.Average(x => x.Volume);
            var currentVolume = data[currentIndex].Volume;

            return avgVolume > 0 ? currentVolume / avgVolume : 1.0;
        }

        /// <summary>
        /// 检查是否突破重要价位
        /// </summary>
        private bool IsBreakingImportantLevel(GapData gap, List<MarketDataPoint> data, int currentIndex)
        {
            // 简化实现：检查是否突破近期高点或低点
            var lookbackPeriod = 50;
            var startIndex = Math.Max(0, currentIndex - lookbackPeriod);
            var recentData = data.Skip(startIndex).Take(currentIndex - startIndex).ToList();

            if (!recentData.Any()) return false;

            var recentHigh = recentData.Max(x => x.High);
            var recentLow = recentData.Min(x => x.Low);

            if (gap.Direction == GapDirection.Up)
            {
                return gap.OpenPrice > recentHigh;
            }
            else
            {
                return gap.OpenPrice < recentLow;
            }
        }

        /// <summary>
        /// 检查是否可能是趋势衰竭
        /// </summary>
        private bool IsLikelyTrendExhaustion(List<MarketDataPoint> data, int currentIndex)
        {
            // 简化实现：检查前期趋势是否已持续较长时间
            var trendPeriod = 20;
            var startIndex = Math.Max(0, currentIndex - trendPeriod);
            var trendData = data.Skip(startIndex).Take(currentIndex - startIndex + 1).ToList();

            if (trendData.Count < 10) return false;

            // 检查价格是否连续向同一方向移动
            var upCount = 0;
            var downCount = 0;

            for (int i = 1; i < trendData.Count; i++)
            {
                if (trendData[i].Close > trendData[i - 1].Close)
                    upCount++;
                else if (trendData[i].Close < trendData[i - 1].Close)
                    downCount++;
            }

            var totalCount = trendData.Count - 1;
            var trendRatio = Math.Max(upCount, downCount) / (double)totalCount;

            return trendRatio > 0.7; // 70%以上同向移动
        }

        /// <summary>
        /// 获取历史填补率
        /// </summary>
        private double GetHistoricalFillRate(GapType gapType)
        {
            // 基于技术分析经验的默认填补率
            return gapType switch
            {
                GapType.Common => 0.90,      // 普通缺口填补率最高
                GapType.Breakaway => 0.30,   // 突破缺口填补率较低
                GapType.Runaway => 0.25,     // 持续缺口填补率最低
                GapType.Exhaustion => 0.85,  // 衰竭缺口填补率很高
                _ => 0.70
            };
        }

        /// <summary>
        /// 计算大小调整系数
        /// </summary>
        private double CalculateSizeAdjustment(double gapPercentage)
        {
            var absGap = Math.Abs(gapPercentage);
            
            if (absGap < 0.5) return 1.2;      // 小缺口更容易填补
            if (absGap < 1.0) return 1.0;      // 中等缺口正常填补
            if (absGap < 2.0) return 0.8;      // 大缺口不易填补
            return 0.6;                        // 特大缺口很难填补
        }

        /// <summary>
        /// 计算成交量调整系数
        /// </summary>
        private double CalculateVolumeAdjustment(List<MarketDataPoint> data, int currentIndex)
        {
            var volumeRatio = CalculateVolumeRatio(data, currentIndex, 10);
            
            if (volumeRatio > 2.0) return 0.8;     // 异常高成交量降低填补概率
            if (volumeRatio > 1.5) return 0.9;     // 高成交量
            if (volumeRatio < 0.5) return 1.1;     // 低成交量提高填补概率
            return 1.0;                            // 正常成交量
        }

        /// <summary>
        /// 计算趋势调整系数
        /// </summary>
        private double CalculateTrendAdjustment(List<MarketDataPoint> data, int currentIndex)
        {
            var trendStrength = Math.Abs(CalculateTrendStrength(data, currentIndex, 10));
            
            if (trendStrength > 0.1) return 0.7;   // 强趋势中缺口不易填补
            if (trendStrength > 0.05) return 0.85; // 中等趋势
            return 1.15;                           // 无明显趋势时易填补
        }

        /// <summary>
        /// 计算置信度
        /// </summary>
        private double CalculateConfidence(GapData gap, List<MarketDataPoint> data, int currentIndex)
        {
            // 基于数据质量和分析条件计算置信度
            var dataQuality = Math.Min(1.0, (double)Math.Min(currentIndex, 50) / 50.0);
            var volumeQuality = data[currentIndex].Volume > 0 ? 1.0 : 0.5;
            var typeConfidence = gap.Type switch
            {
                GapType.Common => 0.9,
                GapType.Breakaway => 0.8,
                GapType.Runaway => 0.8,
                GapType.Exhaustion => 0.7,
                _ => 0.6
            };

            return (dataQuality + volumeQuality + typeConfidence) / 3.0;
        }

        #endregion
    }
}


